package com.reactim.message.security;

import com.reactim.message.connection.ConnectionManager;
import com.reactim.message.config.ConnectionConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 连接清理服务
 * 负责清理超时连接、过期数据和维护连接健康状态
 */
@Service
@Slf4j
public class ConnectionCleanupService {
    
    private final ConnectionManager connectionManager;
    private final ConnectionAccessControl accessControl;
    private final ConnectionValidator validator;
    private final ConnectionConfig connectionConfig;
    private final String instanceId;

    public ConnectionCleanupService(
            @Qualifier("cachedConnectionManager") ConnectionManager connectionManager,
            ConnectionAccessControl accessControl,
            ConnectionValidator validator,
            ConnectionConfig connectionConfig,
            String instanceId) {
        this.connectionManager = connectionManager;
        this.accessControl = accessControl;
        this.validator = validator;
        this.connectionConfig = connectionConfig;
        this.instanceId = instanceId;
    }
    
    // 连接健康检查记录
    private final ConcurrentHashMap<Long, Instant> lastHealthCheckMap = new ConcurrentHashMap<>();
    
    /**
     * 定期清理超时连接
     * 每5分钟执行一次
     */
    @Scheduled(fixedRate = 300000) // 5分钟
    public void cleanupExpiredConnections() {
        log.debug("开始清理超时连接");
        
        try {
            // 获取当前实例的所有连接用户
            connectionManager.getConnectionsByInstance(instanceId)
                    .flatMapIterable(connections -> connections)
                    .map(connection -> connection.getInfo().getUserId())
                    .flatMap(this::checkAndCleanupUserConnection)
                    .collectList()
                    .doOnSuccess(results -> {
                        long cleanedCount = results.stream().mapToLong(result -> result ? 1 : 0).sum();
                        if (cleanedCount > 0) {
                            log.info("清理超时连接完成，清理数量: {}", cleanedCount);
                        }
                    })
                    .doOnError(error -> log.error("清理超时连接时发生错误", error))
                    .subscribe();
                    
        } catch (Exception e) {
            log.error("清理超时连接任务执行失败", e);
        }
    }
    
    /**
     * 检查并清理单个用户连接
     */
    private Mono<Boolean> checkAndCleanupUserConnection(Long userId) {
        return connectionManager.getConnection(userId)
                .flatMap(connectionDetails -> {
                    if (connectionDetails == null) {
                        return Mono.just(false);
                    }
                    
                    // 检查连接是否超时
                    long lastActiveTime = connectionDetails.getLastActiveTime();
                    long currentTime = System.currentTimeMillis();
                    long inactiveTime = currentTime - lastActiveTime;
                    long timeoutThreshold = Duration.ofMinutes(connectionConfig.getExpirationTime()).toMillis();
                    
                    if (inactiveTime > timeoutThreshold) {
                        log.info("发现超时连接，准备清理: userId={}, inactiveTime={}ms", userId, inactiveTime);
                        
                        // 清理连接
                        return cleanupUserConnection(userId)
                                .doOnSuccess(success -> {
                                    if (success) {
                                        log.info("超时连接清理成功: userId={}", userId);
                                    }
                                });
                    }
                    
                    return Mono.just(false);
                })
                .onErrorReturn(false);
    }
    
    /**
     * 清理用户连接
     */
    private Mono<Boolean> cleanupUserConnection(Long userId) {
        return connectionManager.removeConnection(userId)
                .flatMap(removed -> {
                    if (removed) {
                        // 减少用户连接计数
                        return accessControl.decrementUserConnectionCount(userId);
                    }
                    return Mono.just(false);
                })
                .doOnSuccess(success -> {
                    // 清理本地健康检查记录
                    lastHealthCheckMap.remove(userId);
                });
    }
    
    /**
     * 定期清理缓存数据
     * 每30分钟执行一次
     */
    @Scheduled(fixedRate = 1800000) // 30分钟
    public void cleanupCacheData() {
        log.debug("开始清理缓存数据");
        
        try {
            // 清理访问控制缓存
            accessControl.cleanupExpiredCache();
            
            // 清理连接验证缓存
            validator.cleanupExpiredRecords();
            
            // 清理健康检查记录
            cleanupHealthCheckRecords();
            
            log.debug("缓存数据清理完成");
            
        } catch (Exception e) {
            log.error("清理缓存数据时发生错误", e);
        }
    }
    
    /**
     * 清理健康检查记录
     */
    private void cleanupHealthCheckRecords() {
        Instant cutoffTime = Instant.now().minus(Duration.ofHours(2));
        
        lastHealthCheckMap.entrySet().removeIf(entry -> 
                entry.getValue().isBefore(cutoffTime));
        
        log.debug("健康检查记录清理完成");
    }
    
    /**
     * 执行连接健康检查
     * 每10分钟执行一次
     */
    @Scheduled(fixedRate = 600000) // 10分钟
    public void performHealthCheck() {
        log.debug("开始执行连接健康检查");
        
        try {
            connectionManager.getConnectionsByInstance(instanceId)
                    .flatMapIterable(connections -> connections)
                    .map(connection -> connection.getInfo().getUserId())
                    .flatMap(this::checkConnectionHealth)
                    .collectList()
                    .doOnSuccess(results -> {
                        long healthyCount = results.stream().mapToLong(result -> result ? 1 : 0).sum();
                        log.debug("连接健康检查完成，健康连接数: {}", healthyCount);
                    })
                    .doOnError(error -> log.error("连接健康检查时发生错误", error))
                    .subscribe();
                    
        } catch (Exception e) {
            log.error("连接健康检查任务执行失败", e);
        }
    }
    
    /**
     * 检查单个连接的健康状态
     */
    private Mono<Boolean> checkConnectionHealth(Long userId) {
        return connectionManager.getConnection(userId)
                .flatMap(connectionDetails -> {
                    if (connectionDetails == null) {
                        return Mono.just(false);
                    }
                    
                    // 发送心跳消息检查连接状态
                    return sendHeartbeat(userId)
                            .doOnSuccess(success -> {
                                if (success) {
                                    lastHealthCheckMap.put(userId, Instant.now());
                                    // 更新最后活跃时间
                                    connectionManager.updateLastActiveTime(userId).subscribe();
                                } else {
                                    log.warn("用户连接健康检查失败: userId={}", userId);
                                }
                            });
                })
                .onErrorReturn(false);
    }
    
    /**
     * 发送心跳消息
     */
    private Mono<Boolean> sendHeartbeat(Long userId) {
        return connectionManager.sendMessageToUser(userId, "heartbeat", "ping")
                .then(Mono.just(true))
                .onErrorReturn(false);
    }
    
    /**
     * 强制清理指定用户的连接
     */
    public Mono<Boolean> forceCleanupUserConnection(Long userId, String reason) {
        log.info("强制清理用户连接: userId={}, reason={}", userId, reason);
        
        return cleanupUserConnection(userId)
                .doOnSuccess(success -> {
                    if (success) {
                        log.info("强制清理用户连接成功: userId={}", userId);
                    } else {
                        log.warn("强制清理用户连接失败: userId={}", userId);
                    }
                });
    }
    
    /**
     * 获取连接统计信息
     */
    public Mono<ConnectionStats> getConnectionStats() {
        return connectionManager.getOnlineUserCount()
                .map(onlineCount -> {
                    int healthCheckCount = lastHealthCheckMap.size();
                    return new ConnectionStats(onlineCount, healthCheckCount);
                });
    }
    
    /**
     * 连接统计信息
     */
    public static class ConnectionStats {
        private final long onlineUserCount;
        private final int healthyConnectionCount;
        
        public ConnectionStats(long onlineUserCount, int healthyConnectionCount) {
            this.onlineUserCount = onlineUserCount;
            this.healthyConnectionCount = healthyConnectionCount;
        }
        
        public long getOnlineUserCount() {
            return onlineUserCount;
        }
        
        public int getHealthyConnectionCount() {
            return healthyConnectionCount;
        }
        
        @Override
        public String toString() {
            return String.format("ConnectionStats{onlineUsers=%d, healthyConnections=%d}", 
                    onlineUserCount, healthyConnectionCount);
        }
    }
}